package eu.codlab.game.gameba.activities;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.content.ClipData.Item;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnKeyListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;
import android.widget.Toast;
import eu.codlab.androidemu.gbcdroid.MediaScanner;
import eu.codlab.androidemu.services.BluetoothServerService;
import eu.codlab.androidemu.services.BluetoothState;
import eu.codlab.androidemu.services.BluetoothStateHelper;
import eu.codlab.androidemu.services.CommandListener;
import eu.codlab.androidemu.utilities.ReportHelper;
import eu.codlab.game.gameba.Emulator;
import eu.codlab.game.gameba.EmulatorView;
import eu.codlab.game.gameba.EmulatorViewCallback;
import eu.codlab.game.gameba.EmulatorViewControl;
import eu.codlab.game.gameba.VirtualKeypad;
import eu.codlab.game.gameba.nonem.input.GameKeyListener;
import eu.codlab.game.gameba.nonem.input.Keyboard;
import eu.codlab.game.gameba.nonem.input.Trackball;
import eu.codlab.src.game.R;

public class GameBoidManager implements GameKeyListener,
DialogInterface.OnCancelListener, CommandListener, OnSharedPreferenceChangeListener {

	private void log(String str1, String str2){
		//Log.d(str1, str2);
	}

	private static int emulatorErrorCode[]=new int[]{
		R.string.gba_error_code_0,
		R.string.gba_error_code_1,
		R.string.gba_error_code_2,
		R.string.gba_error_code_3,
	};
	private boolean _isServerBluetooth;

	public void setActivity(Activity activity){
		_activity = activity;
	}
	private GameBoidManager(Activity activity, boolean isServerBluetooth){
		setActivity(activity);
		_isServerBluetooth = isServerBluetooth;
	}

	public static GameBoidManager getInstance(Activity activity){
		return new GameBoidManager(activity, false);
	}
	public static GameBoidManager getInstance(Activity activity,boolean isServerBluetooth){
		return new GameBoidManager(activity, isServerBluetooth);
	}

	private static Activity _activity;

	public static final int REQUEST_SETTINGS = 3;

	private static final int DIALOG_QUIT_GAME = 1;
	private static final int DIALOG_LOAD_STATE = 2;
	private static final int DIALOG_SAVE_STATE = 3;

	private static final int GAMEPAD_LEFT_RIGHT =
			(Emulator.GAMEPAD_LEFT | Emulator.GAMEPAD_RIGHT);
	private static final int GAMEPAD_UP_DOWN =
			(Emulator.GAMEPAD_UP | Emulator.GAMEPAD_DOWN);
	private static final int GAMEPAD_DIRECTION =
			(GAMEPAD_UP_DOWN | GAMEPAD_LEFT_RIGHT);

	private static Emulator emulator;
	private static int resumeRequested;
	private static Thread emuThread;

	public void checkVars(){
		log("_activity",_activity == null ? "null": "not null");
		log("emuThread",emuThread == null ? "null": "not null");
		log("emulator",emulator == null ? "null": "not null");
	}

	private EmulatorView emulatorView;
	private Keyboard keyboard;
	private EmulatorViewControl keypad;
	private eu.codlab.game.gameba.VirtualKeypad keypad_software; //for bluetooth, not used elsewhere
	private Trackball trackball;

	private String currentGame;
	private String lastPickedGame;
	private boolean isMenuShowing;
	private int quickLoadKey;
	private int quickSaveKey;
	private MediaScanner mediaScanner;

	public Emulator getInstance(){
		return emulator;
	}

	public SharedPreferences getPreferences(int type){
		return _activity.getSharedPreferences("eu.codlab.src.game_preferences", type);
	}

	public void onCreate(Bundle savedInstanceState){
		File f = new File(Environment.getExternalStorageDirectory(), "test.cheat");
		/*try{
			// Create file 
			FileWriter fstream = new FileWriter(f);
			log("test",f.toString());
			//Toast.makeText(_activity,f.toString(),Toast.)
			BufferedWriter out = new BufferedWriter(fstream);
			out.write("PAR_v15 test\n");
			out.write("020309B4 1DA55900"); 
			out.write("020309B8 A5CFE16E"); 
			out.write("020309BC E8D5E6BE");
			out.write("020309C0 FFDFD5E8");
			out.write("020309C4 0202FFFF");
			out.write("020309C8 E6E3E0C0"); 
			out.write("020309CC 0FFFFFD5");
			out.write("020309D0 000051A8");
			out.write("020309D4 4D9F4D9A");
			out.write("020309D8 4D9F4D9A");
			out.write("020309DC 4D9F4D9A");
			out.write("020309E0 20EFEB7A");
			out.write("020309E4 87954791");
			out.write("020309E8 BF95714A");
			out.write("020309EC B930B9E3");
			out.write("020309F0 B879AABE");
			out.write("020309F4 B728F891");
			out.write("020309F8 B84AB936");
			out.write("020309FC B923B851");
			out.write("02030A00 AC7EAC7A");
			out.write("BA6D6DF7 DE9213D6");
			//out.write("DD60E1F2 6E500457\n");
			//out.write("5EE40202 00440063\n");
			//out.write("B58A1B27 2005EF68\n");
			//out.write("30AABA80 270DBFDF\n");
			out.write(" \n \n");
			out.write("RAW testraw\n");
			out.write("64042784 00002060\n");
			out.write(" \n \n");
			out.write("PAR_v5 test\n");
			/*out.write("020309B4 1DA55900"); 
			out.write("020309B8 A5CFE16E"); 
			out.write("020309BC E8D5E6BE");
			out.write("020309C0 FFDFD5E8");
			out.write("020309C4 0202FFFF");
			out.write("020309C8 E6E3E0C0"); 
			out.write("020309CC 0FFFFFD5");
			out.write("020309D0 000051A8");
			out.write("020309D4 4D9F4D9A");
			out.write("020309D8 4D9F4D9A");
			out.write("020309DC 4D9F4D9A");
			out.write("020309E0 20EFEB7A");
			out.write("020309E4 87954791");
			out.write("020309E8 BF95714A");
			out.write("020309EC B930B9E3");
			out.write("020309F0 B879AABE");
			out.write("020309F4 B728F891");
			out.write("020309F8 B84AB936");
			out.write("020309FC B923B851");
			out.write("02030A00 AC7EAC7A");
			//out.write("BC33578D82482A93");
			//out.write("DD60E1F2 6E500457\n");
			//out.write("5EE40202 00440063\n");
			//out.write("B58A1B27 2005EF68\n");
			//out.write("30AABA80 270DBFDF\n");
			//out.write("E1F2DD60 04576E50\n");
			//out.write("02025EE4 00630044\n");
			//out.write("1B27B58A EF682005\n");
			//out.write("BA8030AA BFDF270D\n");
			//Close the output stream
			out.close();
		}catch (Exception e){//Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}*/
		if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2){
			try{
				_activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
			}catch(Exception e){

			}
			_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
		}

		File datadir = _activity.getDir("data", Activity.MODE_PRIVATE);
		if (!initEmulator(datadir)) {
			_activity.finish();
			return;
		}

		if(_isServerBluetooth || (_activity.getIntent() != null &&
				(_activity.getIntent().getBooleanExtra("console", false) == true ||
				(_activity.getIntent().getExtras()!= null && _activity.getIntent().getExtras().getBoolean("console") == true)))){

			final Intent i = new Intent(_activity, BluetoothServerService.class);
			_activity.startService(i);

			_activity.setContentView(R.layout.gba_main_console);
			BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
			if(adapter == null || adapter.isEnabled() == false){
				showErrorBluetooth();
			}


			Thread t = new Thread(){
				public void run(){
					while(BluetoothServerService.getInstance() == null){
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					BluetoothServerService.getInstance().setCommandListener(GameBoidManager.this);
				}
			};
			t.start();
		}else{
			_activity.setContentView(R.layout.gba_main);
		}

		emulatorView = (EmulatorView)_activity.findViewById(R.id.emulator);
		if(emulatorView != null){
			emulatorView.setEmulator(emulator);
		}

		switchToView(R.id.empty);

		// create physical keyboard and trackball
		keyboard = new Keyboard(emulatorView, this);
		trackball = new Trackball(keyboard, this);

		// create virtual keypad
		keypad = (EmulatorViewControl)_activity.findViewById(R.id.keypad);
		if(keypad != null)
			keypad_software = keypad.getVirtualKeypad();
		else
			keypad_software = new VirtualKeypad(_activity);

		keypad_software.setGameKeyListener(this);


		emulatorView.requestFocus();
		if(keypad != null && false == this.getPreferences(Activity.MODE_PRIVATE).getBoolean("stretchcontrol", true))
			emulatorView.setSurroundControllers(keypad);
		else
			emulatorView.setSurroundControllers(null	);


		if(emulatorView != null){
			emulatorView.setOnKeyListener(new OnKeyListener(){

				@Override
				public boolean onKey(View arg0, int keyCode, KeyEvent event) {
					if(keyboard != null)
						return keyboard.onKey(arg0, keyCode, event);
					return false;
				}

			});
		}

		View v = (View)_activity.findViewById(R.principal.adview);
		if(v != null){
			v.setOnKeyListener(new OnKeyListener(){

				@Override
				public boolean onKey(View arg0, int keyCode, KeyEvent event) {
					if(keyboard != null)
						return keyboard.onKey(arg0, keyCode, event);
					return false;
				}

			});
		}

		if(keypad != null){
			keypad.requestFocus();
			keypad.setOnKeyListener(new OnKeyListener(){

				@Override
				public boolean onKey(View arg0, int keyCode, KeyEvent event) {
					if(keyboard != null)
						return keyboard.onKey(arg0, keyCode, event);
					return false;
				}

			});
			keypad.setOnFocusChangeListener(new OnFocusChangeListener(){

				@Override
				public void onFocusChange(View arg0, boolean arg1) {
					if(arg1 == false){
						keypad.requestFocus();
					}
				}

			});
		}
		// copy preset files
		copyAsset(new File(datadir, "game_config.txt"));
		copyAsset(new File(datadir, "g.bin"));

		// load settings
		SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
		settings.registerOnSharedPreferenceChangeListener(this);
		lastPickedGame = settings.getString("lastPickedGame", null);
		loadGlobalSettings();

		resetBios(datadir);

		// restore state if any
		switchToView(R.id.game);

		if(1==1){
			String path = getROMFilePath();
			log("loading",path);
			if(path.endsWith(".gba") || path.endsWith(".bin") || path.endsWith(".zip")){
				lastPickedGame = path;
				loadROM(path);
			}

			// load BIOS
			loadBIOS(settings.getString("bios", null));
			// restore last running game
			String last = settings.getString("lastGame", null);
			log("Last",last);
			if (last != null) {
				if (new File(getGameStateFile(last, 0)).exists() &&
						loadROM(last, false))
					quickLoad();
			}
		}
	}


	private void resetBios(File datadir){
		loadBIOS(new File(datadir, "g.bin").getAbsolutePath());
	}

	private void resetBios(){
		File datadir = _activity.getDir("data", Activity.MODE_PRIVATE);
		resetBios(datadir);
	}

	private String getROMFilePath() {
		return _activity.getSharedPreferences("files", 0).getString("file", "NoLocalFile");
	}

	protected void onDestroy() {
		quickSave();
		if (_activity.isFinishing()) {
			resumeRequested = 0;
			if(emulator != null)
				emulator.cleanUp();
			emulator = null;
		}
	}

	protected void onPause() {
		quickSave();
		pauseEmulator();
	}

	protected void onResume() {

		emulatorView = (EmulatorView)_activity.findViewById(R.id.emulator);
		if(emulatorView != null && emulator != null){
			//emulator.setRenderSurface(emulatorView, 0,0);
			emulatorView.setEmulator(emulator);
		}

		loadGlobalSettings();
		resumeEmulator();
		quickLoad();
	}

	protected void onStop() {
		SharedPreferences.Editor editor = this.getPreferences(Activity.MODE_PRIVATE).edit();
		editor.putString("lastPickedGame", lastPickedGame);
		editor.commit();
		quickSave();
	}

	protected void onSaveInstanceState(Bundle outState) {
		outState.putString("currentGame", currentGame);
		quickSave();
	}

	protected void onRestoreInstanceState(Bundle savedInstanceState){
		if (savedInstanceState != null){
			currentGame = savedInstanceState.getString("currentGame");
		}
	}

	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case DIALOG_LOAD_STATE:
			return createLoadStateDialog();
		case DIALOG_SAVE_STATE:
			return createSaveStateDialog();
		case DIALOG_QUIT_GAME:
			return createQuitGameDialog();
		default:
			return null;
		}
	}

	protected void onPrepareDialog(int id, Dialog dialog) {
		switch (id) {
		case DIALOG_QUIT_GAME:
		case DIALOG_LOAD_STATE:
		case DIALOG_SAVE_STATE:
			pauseEmulator();
			break;
		}
	}

	public boolean onKeyUp(int keyCode, KeyEvent event){
		if(keyboard != null)
			return this.keyboard.onKey(emulatorView, keyCode, event);
		return false;
	}

	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == quickLoadKey) {
			quickLoad();
			return true;
		}
		if (keyCode == quickSaveKey) {
			quickSave();
			return true;
		}
		if (keyCode == KeyEvent.KEYCODE_BACK && currentGame != null) {
			_activity.showDialog(DIALOG_QUIT_GAME);
			return true;
		}
		if(keyboard != null)
			return this.keyboard.onKey(emulatorView, keyCode, event);
		return false;
	}

	public boolean onCreateOptionsMenu(Menu menu) {
		_activity.getMenuInflater().inflate(R.menu.gba_main, menu);
		if(_activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE){
			menu.findItem(R.id.menu_block_screen).setChecked(true);
			menu.findItem(R.id.menu_block_screen).setIcon(R.drawable.check);
		}else{
			menu.findItem(R.id.menu_block_screen).setChecked(false);
			menu.findItem(R.id.menu_block_screen).setIcon(R.drawable.uncheck);
		}
		return true;
	}

	public void onOptionsMenuClosed(Menu menu) {
		if (isMenuShowing) {
			isMenuShowing = false;
			resumeEmulator();
		}
	}

	public boolean onOptionsItemSelected(MenuItem item) {
		if (isMenuShowing) {
			isMenuShowing = false;
			resumeEmulator();
		}

		switch (item.getItemId()) {
		case R.id.menu_block_screen:
			if(item != null){
				if(item.isChecked())
					item.setIcon(R.drawable.uncheck);
				else
					item.setIcon(R.drawable.check);
				item.setChecked(!item.isChecked());
			}
			if(item.isChecked()){
				_activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
			}else{
				_activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
			}
			return true;
		case R.id.menu_screenshot:
			onScreenshot();
			return true;

		case R.id.menu_settings:
			_activity.startActivityForResult(
					new Intent(_activity, GamePreferences.class), REQUEST_SETTINGS);
			return true;

		case R.id.menu_reset:
			emulator.reset();
			return true;

		case R.id.menu_save_state:
			_activity.showDialog(DIALOG_SAVE_STATE);
			return true;

		case R.id.menu_load_state:
			_activity.showDialog(DIALOG_LOAD_STATE);
			return true;

		case R.id.menu_close:
			unloadROM();
			return true;

		case R.id.menu_quit:
			_activity.finish();
			return true;
		}
		return false;
	}

	@Override
	public void onGameKeyChanged() {
		int states = 0;
		if(keyboard != null)
			states |= keyboard.getKeyStates();
		if(keypad_software != null)
			states |= keypad_software.getKeyStates();

		if(trackball != null){
			if ((states & GAMEPAD_DIRECTION) != 0)
				trackball.reset();
			else
				states |= trackball.getKeyStates();
		}

		// resolve conflict keys
		if ((states & GAMEPAD_LEFT_RIGHT) == GAMEPAD_LEFT_RIGHT)
			states &= ~GAMEPAD_LEFT_RIGHT;
		if ((states & GAMEPAD_UP_DOWN) == GAMEPAD_UP_DOWN)
			states &= ~GAMEPAD_UP_DOWN;

		if(emulator != null)
			emulator.setKeyStates(states);
	}

	@Override
	public void onCancel(DialogInterface dialog) {
		resumeEmulator();
	}

	private boolean initEmulator(File datadir) {
		if (emulator != null){
			if (emuThread == null) { 
				emuThread = new Thread() {
					@Override
					public void run() {
						emulator.run();
					}
				};
				emuThread.start();
			}
			return true;
		}

		final String libdir = "/data/data/" + _activity.getPackageName() + "/lib";
		emulator = new Emulator();
		log("initializing emulator",""+getPreferences(Activity.MODE_PRIVATE).getInt("rompak_mega",32));
		if (!emulator.initialize(getPreferences(Activity.MODE_PRIVATE).getInt("rompak_mega",32),
				libdir, datadir.getAbsolutePath()))
			return false;

		if (emuThread == null) { 
			emuThread = new Thread() {
				@Override
				public void run() {
					emulator.run();
				}
			};
			emuThread.start();
		}
		return true;
	}

	private void resumeEmulator() {
		//if (resumeRequested++ == 0) {
		if(keyboard != null)
			keyboard.reset();
		if(keypad_software != null)
			keypad_software.reset();
		if(trackball != null)
			trackball.reset();
		onGameKeyChanged();

		emulator.resume();
		//}
	}

	private void pauseEmulator() {
		//if (--resumeRequested == 0)
		if(emulator != null)
			emulator.pause();
	}


	private class ScreenShotReceiver implements EmulatorViewCallback{
		private final File _path;
		private final boolean _show;

		public ScreenShotReceiver(File path, boolean show){
			_path = path;
			_show = show;
		}

		@Override
		public void onScreenRefresh(Bitmap bitmap) {
			FileOutputStream out = null;
			try {
				try {
					out = new FileOutputStream(_path);
					bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
					bitmap.recycle();

					if(_show){
						_activity.runOnUiThread(new Runnable(){
							public void run(){
								Toast.makeText(_activity, R.string.screenshot_saved,
										Toast.LENGTH_SHORT).show();

							}
						});
					}

					if (mediaScanner == null)
						mediaScanner = new MediaScanner(_activity);
					mediaScanner.scanFile(_path.getAbsolutePath(), "image/png");

				} finally {
					if (out != null)
						out.close();
				}
			} catch (IOException e) {}
		}

	}
	private void onScreenshot() {
		File dir = new File(Environment.getExternalStorageDirectory(),"screenshot");
		if (!dir.exists() && !dir.mkdir()) {
			return;
		}

		String name = Long.toString(System.currentTimeMillis()) + ".png";
		File file = new File(dir, name);
		onScreenshot(file.getAbsolutePath(), true);
	}

	private void onScreenshot(String to_file, boolean show) {
		File file = new File(to_file);
		ScreenShotReceiver screenshotreceiver = new ScreenShotReceiver(file, show);
		emulatorView.waitingScreenShotNextRefresh(screenshotreceiver);
	}
	private boolean copyAsset(File file) {
		if (file.exists())
			return true;

		InputStream in = null;
		OutputStream out = null;

		try {
			in = _activity.getAssets().open(file.getName());
			out = new FileOutputStream(file);

			byte[] buf = new byte[8192];
			int len;
			while ((len = in.read(buf)) > 0)
				out.write(buf, 0, len);

		} catch (Exception e) {
			e.printStackTrace();
			return false;

		} finally {
			try {
				if (out != null)
					out.close();
				if (in != null)
					in.close();
			} catch (IOException e) {
			}
		}
		return true;
	}

	private static int getScalingMode(String mode) {
		if (mode.equals("original"))
			return EmulatorView.SCALING_ORIGINAL;
		if (mode.equals("proportional"))
			return EmulatorView.SCALING_PROPORTIONAL;
		return EmulatorView.SCALING_STRETCH;
	}

	private void saveLastRunningGame(String game) {
		SharedPreferences.Editor editor = this.getPreferences(Activity.MODE_PRIVATE).edit();
		editor.putString("lastGame", game);
		editor.commit();
	}

	private void loadGlobalSettings() {
		pauseEmulator();

		SharedPreferences settings =
				PreferenceManager.getDefaultSharedPreferences(_activity);
		if(emulator != null){
			emulator.setOption("autoFrameSkip",
					settings.getBoolean("autoFrameSkip", true));
			emulator.setOption("maxFrameSkips",
					Integer.toString(settings.getInt("maxFrameSkips", 2)));
			emulator.setOption("soundEnabled", 
					settings.getBoolean("soundEnabled", true));
		}

		if(trackball != null)
			trackball.setEnabled(settings.getBoolean("enableTrackball", false));

		if(keypad != null)
			keypad.setVisibility(settings.getBoolean("enableVirtualKeypad",
					GamePreferences.getDefaultVirtualKeypadEnabled(_activity)) ?
							View.VISIBLE : View.GONE);

		if(emulatorView != null)
			emulatorView.setScalingMode(getScalingMode(
					settings.getString("scalingMode", "proportional")));

		// key bindings
		final int[] gameKeys = GamePreferences.gameKeys;
		final String[] prefKeys = GamePreferences.keyPrefKeys;
		final int[] defaultKeys = GamePreferences.getDefaultKeys(_activity);

		if(keyboard != null){
			keyboard.clearKeyMap();
			for (int i = 0; i < prefKeys.length; i++) {
				keyboard.mapKey(gameKeys[i],
						settings.getInt(prefKeys[i], defaultKeys[i]));
			}
		}

		// shortcut keys
		quickLoadKey = settings.getInt("quickLoad", 0);
		quickSaveKey = settings.getInt("quickSave", 0);

		resumeEmulator();
	}

	private void switchToView(int id) {
		final int viewIds[] = {
				R.id.empty,
				//R.id.game
		};
		for (int i = 0; i < viewIds.length; i++) {
			_activity.findViewById(viewIds[i]).setVisibility(
					viewIds[i] == id ? View.VISIBLE : View.INVISIBLE);
		}
	}

	private class SelectAdapter extends BaseAdapter{
		public SelectAdapter(){
		}
		@Override
		public int getCount() {
			return 10;
		}

		@Override
		public Object getItem(int arg0) {
			return null;
		}

		@Override
		public long getItemId(int arg0) {
			return arg0;
		}

		@Override
		public View getView(int arg0, View arg1, ViewGroup arg2) {
			View v = _activity.getLayoutInflater().inflate(R.layout.select_state_item, null);
			TextView tv = (TextView)v.findViewById(R.state.name);
			tv.setText(" "+arg0);

			String img = loadGameStatePng(arg0);
			if(img != null){
				ImageView image = (ImageView)v.findViewById(R.state.screen);
				Bitmap imagebmp = BitmapFactory.decodeFile(img);
				image.setImageBitmap(imagebmp);
			}

			return v;
		}

	}

	private Dialog createLoadStateDialog() {
		DialogInterface.OnClickListener l =
				new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				loadGameState(which);
				resumeEmulator();
			}
		};

		return new AlertDialog.Builder(_activity).
				setTitle(R.string.gba_load_state_title).
				setAdapter(new SelectAdapter(), l).
				setOnCancelListener(this).create();
	}

	private Dialog createSaveStateDialog() {
		DialogInterface.OnClickListener l =
				new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				saveGameState(which, true);
				resumeEmulator();
			}
		};

		return new AlertDialog.Builder(_activity).
				setTitle(R.string.gba_load_state_title).
				setAdapter(new SelectAdapter(), l).
				setOnCancelListener(this).create();
	}

	private Dialog createQuitGameDialog() {
		DialogInterface.OnClickListener l =
				new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				switch (which) {
				/*case 0:
					resumeEmulator();
					onLoadROM();
					break;*/
				case 1:
					quickSave();
					saveLastRunningGame(currentGame);
					// fall through
				case 2:
					_activity.finish();
					break;
				}
			}
		};

		return new AlertDialog.Builder(_activity).
				setTitle(R.string.gba_quit_game_title).
				setItems(R.array.gba_exit_game_options, l).
				setOnCancelListener(this).create();
	}


	String biosFileName = "";
	private boolean loadBIOS(String name) {
		biosFileName = name;
		log("begin loadBios", ""+name);
		if (name != null && emulator.loadBIOS(name)) {

			SharedPreferences.Editor editor =
					this.getPreferences(Activity.MODE_PRIVATE).edit();
			editor.putString("bios", biosFileName);
			editor.commit();
			return true;
		}

		return false;
	}

	private boolean loadROM(String fname) {
		return loadROM(fname, true);
	}

	String romFileName = "";
	private boolean loadROM(final String fname, boolean failPrompt) {
		unloadROM();
		romFileName = fname;

		if (!emulator.loadROM(fname) && failPrompt) {
			Toast.makeText(_activity, R.string.gba_load_rom_failed,
					Toast.LENGTH_SHORT).show();
			Toast.makeText(_activity, "Loading : "+romFileName,
					Toast.LENGTH_SHORT).show();
			DialogInterface.OnClickListener l =
					new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					switch (which) {
					case DialogInterface.BUTTON_POSITIVE:
						sendReport(1);
						break;
					case DialogInterface.BUTTON_NEGATIVE:
						_activity.finish();
						break;
					}
				}
			};

			int res; 
			switch(emulator.getErrorCode()){
			case -1:
				res = R.string.gba_error_code_1;
				break;
			case -2:
				res = R.string.gba_error_code_2;
				break;
			case -3:
				res = R.string.gba_error_code_3;
				break;
			case 0:
			default:
				res = R.string.gba_error_code_0;
				break;
			}
			new AlertDialog.Builder(_activity).
			setCancelable(false).
			setTitle(R.string.gba_load_failed).
			setMessage(res).
			setPositiveButton(R.string.gba_load_failed_send, l).
			setNegativeButton(R.string.gba_quit, l).
			show();



			log("loadRom",emulator.getErrorCode()+"");
			return false;
		}

		log("loadRom",emulator.getErrorCode()+"");

		currentGame = fname;
		saveLastRunningGame(currentGame);
		switchToView(R.id.game);
		return true;
	}

	private void sendReport(int type){
		int error = 0;
		if(emulator != null)
			error=emulator.getErrorCode();
		ReportHelper.sendReport(_activity, type, _activity.getClass(), getROMFilePath(), error);
	}
	private void unloadROM() {
		if (currentGame != null) {
			emulator.unloadROM();
			currentGame = null;
			//switchToView(R.id.empty);
		}
	}

	private void saveGameState(int slot,boolean screen) {
		if(emulator != null){
			String fname = getGameStateFile(currentGame, slot);
			if(screen){
				onScreenshot(fname+".png", false);
			}
			emulator.saveState(fname);
		}
	}

	private void loadGameState(int slot) {
		final String fname = getGameStateFile(currentGame, slot);
		if (new File(fname).exists() && emulator != null){
			emulator.loadState(fname);
			Thread t = new Thread(){
				public void run(){
					try{
						Thread.sleep(1);
					}catch(Exception e){

					}
					onScreenshot(fname+".png", false);
				}
			};
			t.start();
		}
	}

	private String loadGameStatePng(int slot) {
		String fname = getGameStateFile(currentGame, slot);
		if(fname.lastIndexOf(".gba") > 0)
			fname = fname.substring(0, fname.lastIndexOf(".gba"));
		log("loadGameState",fname+".png");
		if (new File(fname+".png").exists())
			return fname+".png";
		return null;
	}

	private void quickSave() {
		saveGameState(0,_activity.isFinishing() ? false : true);
	}

	private void quickLoad() {
		loadGameState(0);
	}

	private static String getGameStateFile(String name, int slot) {
		int i = name.lastIndexOf('.');
		if (i >= 0)
			name = name.substring(0, i);
		name += ".ss" + slot;
		return name;
	}


	@Override
	public void showErrorBluetooth() {

		DialogInterface.OnClickListener l =
				new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				switch (which) {
				case DialogInterface.BUTTON_POSITIVE:
					break;
				}
			}
		};

		new AlertDialog.Builder(_activity).
		setCancelable(false).
		setTitle(R.string.gba_console_bluetooth_error_title).
		setMessage(R.string.gba_console_bluetooth_error_message).
		setPositiveButton(R.string.gba_quit, l).
		show();
	}

	@Override
	public void onCommand(int command, int state) {
		keypad_software.onKeyFromClient(null, command, state);
	}


	@Override
	public void onBluetoothState(final BluetoothState state) {
		_activity.runOnUiThread(new Thread(){
			public void run(){
				Toast.makeText(_activity, BluetoothStateHelper.getResourceFromBluetoothStateServer(state), Toast.LENGTH_LONG).show();
			}
		});
	}

	@Override
	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
			String key) {
		loadGlobalSettings();
	}
}
